<?php

/**
 * Configuration class. Cinnamon configuration is stored in database. This class provides the 
 * necessary methods to insert, update and retrieve options
 */
class Configuration {
	protected $options;
	
	/**
	 * Defaults constructor.
	 */
	public function __construct() {
		$db = Cinnamon::registry('db');
		
		// autoload options
		$sql = "SELECT option_name, option_value "
			  ."FROM $db->options "
			  ."WHERE option_autoload='y'";
		$options = $db->getIterator($sql);
		foreach ( $options as $option ) {
			$this->options[$option->option_name] = $db->unescape($option->option_value);
		}
	}
	
	/**
	 * Adds a new option to the database. If a conflict occurs, an exception will be thrown.
	 * 
	 * @param string name option name. Use dots to separate multiple levels of hierarchy, ex plugins.active Try to avoid names such as plugins_active or active_plugins.
	 * @param mixed value the value of the specified option. If is an object or array, it will be serialized.
	 * @param boolean autoload defines whether or not the option should be loaded automatically. Use this option, only for frequently used options.
	 * @return true only and only if the option added successfully.
	 */
	public function add($name, $value, $autoload) {
		if ( $this->exists($name) ) {
			throw new Exception('Option already exists('. $name .')');
		}
		
		$db = Cinnamon::registry('db');
		
		$autoload = ( $autoload ) ? 'y' : 'n';
		
		$sql = "INSERT INTO $db->options (option_name, option_value, option_autoload) "
			  ."VALUES ('". $db->escape($name) ."', '". $db->escape($value) ."', '$autoload')";
		$rows = $db->query($sql);
		if ( $rows > 0 ) {
			$this->options[$name] = $value;
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Updates an option that already exists. If the specified option does not exist, an exception will be thrown.
	 *
	 * @param string name the option to be updated
	 * @param mixed value the new value
	 * @return true only and only if the option updated succesfully
	 */
	public function set($name, $value) {
		if ( !$this->exists($name) ) {
			throw new Exception('Option does not exist('. $name .')');
		}
		
		$db = Cinnamon::registry('db');
		
		$sql = "UPDATE $db->options SET option_value = '".  $db->escape($value) ."' "
			  ."WHERE option_name = '". $db->escape($name) ."'";
		$rows = $db->query($sql);
		if ( $rows > 0 ) {
			$this->options[$name] = $value;
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Returns true if an option with specified name exists
	 *
	 * @param string name the option name
	 * @param true only and only if the option exists
	 */
	public function exists($name) {
		if ( isset($this->options[name]) ) {
			return true;
		}
		
		$db = Cinnamon::registry('db');
		
		$sql = "SELECT COUNT(option_id) FROM $db->options WHERE option_name='". $db->escape($name) ."'";
		$value = $db->getValue($sql);
		return ( $value > 0 );
	}
	
	/**
	 * Returns the value for the specified option
	 *
	 * @param string name the option name
	 * @return the option value
	 */
	public function get($name) {
		$db = Cinnamon::registry('db');
		if ( !isset($this->options[$name]) && $this->exists($name) ) {
			$value = $db->getValue("SELECT option_value FROM $db->options WHERE option_name='". $db->escape($name) ."'");
			$this->options[$name] = $db->unescape($value);
		}
		return $this->options[$name];
	}
	
	/**
	 * Returns an array of values that matches the specified pattern. Use * for one or more unknown characters.
	 *
	 * @param string name the name pattern to be matched
	 * @return array an array of values
	 */
	public function getAll($name) {
		$name = str_replace('*', '%', $name);
		
		$db = Cinnamon::registry('db');
		
		$options = array();
		$itr = $db->getIterator("SELECT option_name, option_value FROM $db->options WHERE option_name LIKE '". $db->escape($name) ."'");
		foreach ( $itr as $option ) {
			$this->options[$option->option_name] = $db->unescape($option->option_value);
			$options[$option->option_name] = $this->options[$option->option_name];
		}
		return $options;
	}
	
	/** 
	 * Removes the spefified option from the database
	 *
	 * @param string name the name of the option to be removed
	 * @return true if and only if the specified option has been removed successfuly
	 */
	public function remove($name) {
		if ( !$this->exists($name) ) {
			return false;
		}
		
		$sql = "DELETE FROM $db->options WHERE option_name='". $db->escape($name) ."'";
		$rows = $db->query($sql);
		if ( $rows > 0 ) {
			$this->options = array_key_remove($this->options, $name);
			return true;
		} else {
			return false;
		}		
	}	
}
?>